package com.simple.mqtt.common.tool;

import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * JSON工具类
 * 提供全面的JSON序列化/反序列化功能
 */
public class JsonTool {
    public static final ObjectMapper MAPPER = new ObjectMapper();
    public static final TypeFactory TYPE_FACTORY = MAPPER.getTypeFactory();
    public static final TimeZone TIME_ZONE = TimeZone.getTimeZone("Asia/Shanghai");
    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter LOCAL_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter LOCAL_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
    public static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    static {
        MAPPER.setTimeZone(TIME_ZONE)
                .registerModule(new JavaTimeModule()
                        .addSerializer(LocalDate.class, new LocalDateSerializer(LOCAL_DATE_FORMATTER))
                        .addSerializer(LocalTime.class, new LocalTimeSerializer(LOCAL_TIME_FORMATTER))
                        .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(LOCAL_DATE_TIME_FORMATTER))
                        .addDeserializer(LocalDate.class, new LocalDateDeserializer(LOCAL_DATE_FORMATTER))
                        .addDeserializer(LocalTime.class, new LocalTimeDeserializer(LOCAL_TIME_FORMATTER))
                        .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(LOCAL_DATE_TIME_FORMATTER)))
                .setDateFormat(SIMPLE_DATE_FORMAT)
                .configure(JsonParser.Feature.ALLOW_COMMENTS, true)// 允许JSON注释
                .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)// 允许字符串使用单引号
                .configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true)// 允许非标准数字如NaN、Infinity
                .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)// 允许未加引号的字段名
                .configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true)// 允许数字前导零
                .configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true)// 允许未转义的控制字符
                .configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true)// 允许反斜杠转义任意字符
                //.configure(SerializationFeature.INDENT_OUTPUT, true)// 启用漂亮打印输出
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)// 空bean不失败
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)// 禁用日期作为时间戳序列化
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)// 反序列化时忽略未知属性
                .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);// 将未知枚举值读取为null
    }

    /**
     * 将Java对象转换为JSON字符串
     * @param obj 要转换的对象
     * @return JSON字符串，如果转换失败返回null
     */
    public static String toJsonStr(Object obj) {
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            LogTool.error("将对象转换为JSON字符串失败");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将Java对象转换为字节数组
     * @param obj 要转换的对象
     * @return 字节数组，如果转换失败返回null
     */
    public static byte[] toJsonBytes(Object obj) {
        try {
            return MAPPER.writeValueAsBytes(obj);
        } catch (Exception e) {
            LogTool.error("将对象转换为字节数组失败");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将JSON字符串转换为Java对象
     * @param str JSON字符串
     * @param clazz 目标类
     * @return 对象，如果转换失败返回null
     */
    public static <T> T jsonStrToObj(String str, Class<T> clazz) {
        try {
            return MAPPER.readValue(str, clazz);
        } catch (Exception e) {
            LogTool.error("将JSON字符串转换为对象失败");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将字节数组转换为Java对象
     * @param bytes 字节数组
     * @param clazz 目标类
     * @return 对象，如果转换失败返回null
     */
    public static <T> T bytesToObj(byte[] bytes, Class<T> clazz) {
        try {
            return MAPPER.readValue(bytes, clazz);
        } catch (Exception e) {
            LogTool.error("将字节数组转换为对象失败");
            e.printStackTrace();
            return null;
        }
    }

    @JsonPropertyDescription(value = "将 JSON 字符串转换为 TypeReference")
    public static <T> T jsonStrToType(String str, TypeReference<T> typeReference) {
        try {
            return MAPPER.readValue(str, typeReference);
        } catch (Exception e) {
            LogTool.error("将JSON字符串转换为TypeReference失败");
            e.printStackTrace();
            return null;
        }
    }

    @JsonPropertyDescription(value = "将 byte[]转换为 TypeReference")
    public static <T> T bytesToType(byte[] bytes, TypeReference<T> typeReference) {
        try {
            return MAPPER.readValue(bytes, typeReference);
        } catch (Exception e) {
            LogTool.error("将字节数组转换为TypeReference失败");
            e.printStackTrace();
            return null;
        }
    }

    @JsonPropertyDescription(value = "将 JsonNode 转换为 Java 对象")
    public static <T> T jsonNodeToObj(JsonNode jsonNode, Class<T> clazz) {
        if (jsonNode == null || jsonNode.isEmpty() || clazz == null) {
            return null;
        }
        return MAPPER.convertValue(jsonNode, clazz);
    }

    @JsonPropertyDescription(value = "复制单个 Bean")
    public static <T> T copyBean(Object source, Class<T> targetClass) {
        if (source == null || targetClass == null) {
            return null;
        }
        return MAPPER.convertValue(source, targetClass);
    }

    @JsonPropertyDescription(value = "创建一个新的 ObjectNode")
    public static ObjectNode createObjectNode() {
        return MAPPER.createObjectNode();
    }

    @JsonPropertyDescription(value = "将 Java 对象转换为 ObjectNode")
    public static ObjectNode objToObjectNode(Object obj) {
        try {
            return MAPPER.convertValue(obj, ObjectNode.class);
        } catch (Exception e) {
            LogTool.error("将对象转换为ObjectNode失败");
            e.printStackTrace();
            return createObjectNode();
        }
    }

    @JsonPropertyDescription(value = "将 JSON 字符串转换为 ObjectNode")
    public static ObjectNode jsonStrToObjectNode(String str) {
        try {
            return MAPPER.readValue(str, ObjectNode.class);
        } catch (Exception e) {
            LogTool.error("将JSON字符串转换为ObjectNode失败");
            e.printStackTrace();
            return createObjectNode();
        }
    }

    @JsonPropertyDescription(value = "将 byte[]转换为 ObjectNode")
    public static ObjectNode bytesToObjectNode(byte[] bytes) {
        try {
            return MAPPER.readValue(bytes, ObjectNode.class);
        } catch (Exception e) {
            LogTool.error("将字节数组转换为ObjectNode失败");
            e.printStackTrace();
            return createObjectNode();
        }
    }

    @JsonPropertyDescription(value = "将 Map 转换为 ObjectNode")
    public static ObjectNode mapToObjectNode(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return createObjectNode();
        }
        return MAPPER.convertValue(map, ObjectNode.class);
    }

    @JsonPropertyDescription(value = "将 JsonNode 转换为 ObjectNode")
    public static ObjectNode jsonNodeToObjectNode(JsonNode jsonNode) {
        if (jsonNode == null || jsonNode.isEmpty()) {
            return createObjectNode();
        }
        return MAPPER.convertValue(jsonNode, ObjectNode.class);
    }

    @JsonPropertyDescription(value = "创建一个新的 ArrayNode")
    public static ArrayNode createArrayNode() {
        return MAPPER.createArrayNode();
    }

    @JsonPropertyDescription(value = "将 Java 对象转换为 ArrayNode")
    public static ArrayNode objToArrayNode(Object obj) {
        try {
            return MAPPER.convertValue(obj, ArrayNode.class);
        } catch (Exception e) {
            LogTool.error("Failed to convert Object to ArrayNode");
            e.printStackTrace();
            return createArrayNode();
        }
    }

    @JsonPropertyDescription(value = "将 JSON 字符串转换为 ArrayNode")
    public static ArrayNode jsonStrToArrayNode(String str) {
        try {
            return MAPPER.readValue(str, ArrayNode.class);
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON string to ArrayNode");
            e.printStackTrace();
            return createArrayNode();
        }
    }

    @JsonPropertyDescription(value = "将 byte[]转换为 ArrayNode")
    public static ArrayNode bytesToArrayNode(byte[] bytes) {
        try {
            return MAPPER.readValue(bytes, ArrayNode.class);
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON byte[] to ArrayNode");
            e.printStackTrace();
            return createArrayNode();
        }
    }

    @JsonPropertyDescription(value = "将 JsonNode转换为 ArrayNode")
    public static ArrayNode jsonNodeToArrayNode(JsonNode jsonNode) {
        if (jsonNode == null || jsonNode.isEmpty()) {
            return createArrayNode();
        }
        return MAPPER.convertValue(jsonNode, ArrayNode.class);
    }

    @JsonPropertyDescription(value = "将 Java 对象列表转换为 ArrayNode")
    public static <T> ArrayNode listToJsonArray(Collection<T> list) {
        return MAPPER.valueToTree(list);
    }

    @JsonPropertyDescription(value = "将 Java 对象数组转换为 ArrayNode")
    public static <T> ArrayNode arrayToJsonArray(T[] array) {
        return MAPPER.valueToTree(array);
    }

    @JsonPropertyDescription(value = "将 JsonNode 转换为 Java 对象列表")
    public static <T> List<T> jsonNodeToList(JsonNode jsonNode, Class<T> clazz) {
        return jsonNodeToList(jsonNode, clazz, ArrayList.class);
    }

    public static <T> List<T> jsonNodeToList(JsonNode jsonNode, Class<T> clazz, Class<? extends List> listClass) {
        if (jsonNode == null || jsonNode.isEmpty() || clazz == null || listClass == null) {
            return Collections.emptyList();
        }
        return MAPPER.convertValue(jsonNode, TYPE_FACTORY.constructCollectionType(listClass, clazz));
    }

    public static <T> Set<T> jsonNodeToSet(JsonNode jsonNode, Class<T> clazz) {
        return jsonNodeToSet(jsonNode, clazz, HashSet.class);
    }

    public static <T> Set<T> jsonNodeToSet(JsonNode jsonNode, Class<T> clazz, Class<? extends Set> setClass) {
        if (jsonNode == null || jsonNode.isEmpty() || clazz == null || setClass == null) {
            return Collections.emptySet();
        }
        return MAPPER.convertValue(jsonNode, TYPE_FACTORY.constructCollectionType(setClass, clazz));
    }

    @JsonPropertyDescription(value = "将 JsonNode 转换为 Java 对象数组")
    public static <T> T[] jsonNodeToArray(JsonNode jsonNode, Class<T> clazz) {
        if (jsonNode == null || jsonNode.isEmpty() || clazz == null) {
            return null;
        }
        T[] array = MAPPER.convertValue(jsonNode, TYPE_FACTORY.constructArrayType(clazz));
        return array;
    }

    @JsonPropertyDescription(value = "将 jsonString 转换为 Java 对象列表")
    public static <T> List<T> jsonStrToList(String str, Class<T> clazz) {
        return jsonStrToList(str, clazz, ArrayList.class);
    }

    public static <T> List<T> jsonStrToList(String str, Class<T> clazz, Class<? extends List> listClass) {
        if (str == null || str.isEmpty() || clazz == null || listClass == null) {
            return Collections.emptyList();
        }
        try {
            return MAPPER.readValue(str, TYPE_FACTORY.constructCollectionType(listClass, clazz));
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON String to List");
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

    public static <T> Set<T> jsonStrToSet(String str, Class<T> clazz) {
        return jsonStrToSet(str, clazz, HashSet.class);
    }

    public static <T> Set<T> jsonStrToSet(String str, Class<T> clazz, Class<? extends Set> setClass) {
        if (str == null || str.isEmpty() || clazz == null || setClass == null) {
            return Collections.emptySet();
        }
        try {
            return MAPPER.readValue(str, TYPE_FACTORY.constructCollectionType(setClass, clazz));
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON String to Set");
            e.printStackTrace();
            return Collections.emptySet();
        }
    }

    @JsonPropertyDescription(value = "将 jsonString 转换为 Java 对象数组")
    public static <T> T[] jsonStrToArray(String str, Class<T> clazz) {
        if (str == null || str.isEmpty() || clazz == null) {
            return null;
        }
        try {
            return MAPPER.readValue(str, TYPE_FACTORY.constructArrayType(clazz));
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON String to Array");
            e.printStackTrace();
            return (T[]) new Object[0];
        }
    }


    @JsonPropertyDescription(value = "复制列表中的 Bean")
    public static <T, U> List<U> copyList(Collection<T> sourceCollection, Class<U> targetClass) {
        return copyList(sourceCollection, targetClass, ArrayList.class);
    }

    public static <T, U> List<U> copyList(T[] sourceArray, Class<U> targetClass) {
        return copyList(sourceArray, targetClass, ArrayList.class);
    }

    public static <T, U> List<U> copyList(Collection<T> sourceCollection, Class<U> targetClass, Class<? extends List> listClass) {
        if (sourceCollection == null || sourceCollection.isEmpty() || targetClass == null || listClass == null) {
            return Collections.emptyList();
        }
        return MAPPER.convertValue(sourceCollection, TYPE_FACTORY.constructCollectionType(listClass, targetClass));
    }

    public static <T, U> List<U> copyList(T[] sourceArray, Class<U> targetClass, Class<? extends List> listClass) {
        if (sourceArray == null || sourceArray.length == 0 || targetClass == null || listClass == null) {
            return Collections.emptyList();
        }
        return MAPPER.convertValue(sourceArray, TYPE_FACTORY.constructCollectionType(listClass, targetClass));
    }

    @JsonPropertyDescription(value = "复制列表中的 Bean")
    public static <T, U> Set<U> copySet(Collection<T> sourceCollection, Class<U> targetClass) {
        return copySet(sourceCollection, targetClass, HashSet.class);
    }

    public static <T, U> Set<U> copySet(T[] sourceArray, Class<U> targetClass) {
        return copySet(sourceArray, targetClass, HashSet.class);
    }

    public static <T, U> Set<U> copySet(Collection<T> sourceCollection, Class<U> targetClass, Class<? extends Set> setClass) {
        if (sourceCollection == null || sourceCollection.isEmpty() || targetClass == null || setClass == null) {
            return Collections.emptySet();
        }
        return MAPPER.convertValue(sourceCollection, TYPE_FACTORY.constructCollectionType(setClass, targetClass));
    }

    public static <T, U> Set<U> copySet(T[] sourceArray, Class<U> targetClass, Class<? extends Set> setClass) {
        if (sourceArray == null || sourceArray.length == 0 || targetClass == null || setClass == null) {
            return Collections.emptySet();
        }
        return MAPPER.convertValue(sourceArray, TYPE_FACTORY.constructCollectionType(setClass, targetClass));
    }

    @JsonPropertyDescription(value = "复制数组中的 Bean")
    public static <T, U> U[] copyArray(T[] sourceArray, Class<U> targetClass) {
        if (sourceArray == null || sourceArray.length == 0 || targetClass == null) {
            return null;
        }
        return MAPPER.convertValue(sourceArray, TYPE_FACTORY.constructArrayType(targetClass));
    }

    public static <T, U> U[] copyArray(Collection<T> sourceCollection, Class<U> targetClass) {
        if (sourceCollection == null || sourceCollection.isEmpty() || targetClass == null) {
            return null;
        }
        return MAPPER.convertValue(sourceCollection, TYPE_FACTORY.constructArrayType(targetClass));
    }

    @JsonPropertyDescription(value = "将 JsonNode 转换为 Map")
    public static Map<String, Object> jsonNodeToMap(JsonNode jsonNode) {
        return MAPPER.convertValue(jsonNode, HashMap.class);
    }

    public static Map<String, Object> jsonNodeToMap(JsonNode jsonNode, Class<? extends Map> mapClass) {
        if (jsonNode == null || jsonNode.isEmpty() || mapClass == null) {
            return Collections.emptyMap();
        }
        return MAPPER.convertValue(jsonNode, mapClass);
    }

    @JsonPropertyDescription(value = "将 jsonString 转换为 Map")
    public static Map<String, Object> jsonStrToMap(String str) {
        return jsonStrToMap(str, HashMap.class);
    }

    public static Map<String, Object> jsonStrToMap(String str, Class<? extends Map> mapClass) {
        try {
            return MAPPER.readValue(str, mapClass);
        } catch (Exception e) {
            LogTool.error("Failed to convert JSON String to Map");
            e.printStackTrace();
            return Collections.emptyMap();
        }
    }

    @JsonPropertyDescription(value = "将 Object 转换为 Map")
    public static Map<String, Object> objToMap(Object obj) {
        return objToMap(obj, HashMap.class);
    }

    public static Map<String, Object> objToMap(Object obj, Class<? extends Map> mapClass) {
        if (obj == null || mapClass == null) {
            return Collections.emptyMap();
        }
        return MAPPER.convertValue(obj, mapClass);
    }

    @JsonPropertyDescription(value = "将 Object 转换为 List")
    public static List<Object> objToList(Object obj) {
        return objToList(obj, ArrayList.class);
    }

    public static List<Object> objToList(Object obj, Class<? extends List> listClass) {
        if (obj == null || listClass == null) {
            return Collections.emptyList();
        }
        return MAPPER.convertValue(obj, listClass);
    }

    @JsonPropertyDescription(value = "将 Object 转换为 Set")
    public static Set<Object> objToSet(Object obj) {
        return objToSet(obj, HashSet.class);
    }

    public static Set<Object> objToSet(Object obj, Class<? extends Set> setClass) {
        if (obj == null || setClass == null) {
            return Collections.emptySet();
        }
        return MAPPER.convertValue(obj, setClass);
    }

    /**
     * 广度优先搜索
     */
    @JsonPropertyDescription(value = "广度优先搜索")
    public static JsonNode bfsSearchKey(JsonNode root, String key) {
        Queue<JsonNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            JsonNode current = queue.poll();
            // 检查当前节点是否有key
            if (current.has(key)) {
                return current.get(key);
            }
            // 将子节点加入队列
            if (current.isObject()) {
                current.fields().forEachRemaining(entry -> queue.offer(entry.getValue()));
            } else if (current.isArray()) {
                current.forEach(queue::offer);
            }
        }
        return null;
    }

    @JsonPropertyDescription(value = "合并多个 ObjectNode")
    public static ObjectNode mergeObjectNodes(ObjectNode... nodes) {
        ObjectNode merged = createObjectNode();
        for (ObjectNode node : nodes) {
            if (node != null) {
                node.fields().forEachRemaining(entry -> {
                    merged.set(entry.getKey(), entry.getValue());
                });
            }
        }
        return merged;
    }

    @JsonPropertyDescription(value = "检查 JSON 字符串是否有效")
    public static boolean isValidJson(String json) {
        try {
            JsonParser parser = MAPPER.getFactory().createParser(json);
            JsonNode node = MAPPER.readTree(parser);
            return node != null;
        } catch (Exception e) {
            return false;
        }
    }

    @JsonPropertyDescription(value = "从 JSON 字符串中提取特定路径的值")
    public static JsonNode getValueByPath(String json, String path) {
        try {
            ObjectNode root = jsonStrToObjectNode(json);
            String[] pathElements = path.split("\\.");
            JsonNode current = root;
            for (String element : pathElements) {
                current = current.get(element);
                if (current == null) {
                    return null;
                }
            }
            return current;
        } catch (Exception e) {
            return null;
        }
    }

    @JsonPropertyDescription(value = "将 ObjectNode 转换为格式化的 JSON 字符串")
    public static String objectNodeToFormattedJsonStr(ObjectNode objectNode) {
        try {
            return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(objectNode);
        } catch (Exception e) {
            LogTool.error("Failed to convert ObjectNode to formatted JSON string");
            e.printStackTrace();
            return "";
        }
    }
}